package org.voidness.oje2d;

import java.awt.Dimension;
import java.awt.Image;

import org.lwjgl.opengl.GL11;
import org.voidness.oje2d.interfaces.GLImageInterface;

/** A simple image class. */
public class GLImage implements GLImageInterface {

    private static int list;
    static {
        list = GL11.glGenLists(1000);
        GL11.glNewList(list, GL11.GL_COMPILE);
        drawQuad();
        GL11.glEndList();
    }
    private static void drawQuad(){

        GL11.glBegin(GL11.GL_QUADS);
        {
            GL11.glNormal3f(0.0f, 0.0f, 1.0f);

            GL11.glTexCoord2f(0.0f, 0.0f);
            GL11.glVertex2d(-0.5, -0.5);

            GL11.glTexCoord2f(0.0f, 1.0f);
            GL11.glVertex2d(-0.5, 0.5);

            GL11.glTexCoord2f(1.0f, 1.0f);
            GL11.glVertex2d(0.5, 0.5);

            GL11.glTexCoord2f(1.0f, 0.0f);
            GL11.glVertex2d(0.5, -0.5);
        }
        GL11.glEnd();
    }

    /** The associated texture */
    private GLTexture texture;
    /** The image's width */
    private int width;
    /** The image's height */
    private int height;
    /** The image's relative path */
    private String filename;
    /** Whether this image is a tilable or not. Texture tiling issues. */
    private boolean tile;
    /** How many times we want to tile this image */
    private Dimension tilingValues;
    /** The color to use while drawing the image */
    private GLColor color;
    private int id;

    /**
     * A constructor for the image class.
     * 
     * @param mFilename The path for the image to use
     * @param mWidth The width to use when drawing
     * @param mHeight The height to use when drawing
     * @param mTile Whether we want to tile this image or not
     */
    public GLImage(String mFilename, int mWidth, int mHeight, boolean mTile) {
        filename = mFilename;
        tile = mTile;
        texture = new GLTexture(mFilename, tile);
        width = mWidth;
        height = mHeight;

        // By default we don't want any colors in the texture
        color = GLColor.WHITE;

        calculateTilingValues();

        id = -1;
    }

    /**
     * Another constructor. This one builds an image from a texture
     * 
     * @param mTexture The texture to set
     * @param mWidth The width of the image
     * @param mHeight The height of the image
     * @param mTile Is this image tilable?
     */
    public GLImage(GLTexture mTexture, int mWidth, int mHeight, boolean mTile) {
        tile = mTile;
        texture = mTexture;
        width = mWidth;
        height = mHeight;

        // By default we don't want any colors in the texture
        color = GLColor.WHITE;

        calculateTilingValues();

        id = -1;
    }

    /**
     * Another constructor for the image class. This time no size is defined, so
     * we will use the original image size.
     * 
     * @param mFilename The name of the file to open
     */
    public GLImage(String mFilename) {
        filename = mFilename;
        tile = false;
        texture = new GLTexture(mFilename, tile);
        width = texture.getWidth();
        height = texture.getHeight();

        // By default we don't want any colors in the texture
        color = GLColor.WHITE;

        calculateTilingValues();

        id = -1;
    }

    /**
     * Another constructor for the image
     * 
     * @param mImage The image to associate
     * @param mWidth The width to use when drawing
     * @param mHeight The height to use when drawing
     * @param mTile Whether we want to tile this image or not
     */
    public GLImage(Image mImage, int mWidth, int mHeight, boolean mTile) {
        texture = new GLTexture(mImage, mTile);
        width = mWidth;
        height = mHeight;

        // By default we don't want any colors in the texture
        color = GLColor.WHITE;

        calculateTilingValues();

        id = -1;
    }

    public void setId(int mId) {
        id = mId;
    }

    public int getId() {
        return id;
    }

    /**
     * Calculates the tiling values
     */
    private void calculateTilingValues() {
        tilingValues = new Dimension();

        if (texture.getWidth() == 0 && texture.getHeight() == 0) {
            tilingValues.width = 1;
            tilingValues.height = 1;
            return;
        }

        tilingValues.width = width / texture.getWidth();
        tilingValues.height = height / texture.getHeight();

        if (tilingValues.width == 0) {
            tilingValues.width = 1;
        }
        if (tilingValues.height == 0) {
            tilingValues.height = 1;
        }
    }

    /**
     * Reloads the original image's dimensions
     */
    public void reloadSize() {
        this.width = texture.getWidth();
        this.height = texture.getHeight();
    }

    /**
     * Reloads the texture
     */
    public void reload() {
        texture.reloadData();
    }

    /**
     * Returns the image's relative path
     * 
     * @return The image's filename
     */
    public String getFilename() {
        return filename;
    }

    /**
     * (Re)defines the drawing color for the iamge.
     * 
     * @param mColor The color to use
     */
    public void setColor(GLColor mColor) {
        color = mColor;
    }

    public GLColor getColor() {
        return color;
    }

    /**
     * Gets the texture used by the image.
     * 
     * @return The texture
     */
    public GLTexture getTexture() {
        return texture;
    }

    /**
     * Get the image's width.
     * 
     * @return The width value
     */
    public int getWidth() {
        return width;
    }

    /**
     * Get the image's height.
     * 
     * @return The height value
     */
    public int getHeight() {
        return height;
    }

    /**
     * Redefines the image's width
     * 
     * @param mWidth The new width
     */
    public void setWidth(int mWidth) {
        width = mWidth;
    }

    /**
     * Redefines the image's height
     * 
     * @param mHeight The new height
     */
    public void setHeight(int mHeight) {
        height = mHeight;
    }

    /**
     * Draw the image at mX,mY with full alpha.
     * 
     * @param mX The X position where to draw
     * @param mY The Y position where to draw
     */
    public void draw(int mX, int mY) {
        draw(mX, mY, 1.0f);
    }

    /**
     * Draw the image at mX,mY with custom alpha.
     * 
     * @param mX The X position where to draw
     * @param mY The Y position where to draw
     * @param mAlpha The alpha value to use
     */
    public void draw(int mX, int mY, float mAlpha) {
        GLColor mColor =
                new GLColor(color.getRed(), color.getGreen(), color.getBlue(),
                mAlpha);
        mColor.set();
        GL11.glEnable(GL11.GL_TEXTURE_2D);

        GL11.glDisable(GL11.GL_DEPTH_TEST);
        GL11.glEnable(GL11.GL_BLEND);

        texture.bind();

        GL11.glMatrixMode(GL11.GL_MODELVIEW);
        GL11.glPushMatrix();
        GL11.glTranslated(mX + width / 2.0f, Engine.getInstance().getDisplayBounds().getY() - mY - height / 2.0f, 0);
        GL11.glScaled(getWidth(), getHeight(), 1);
        GL11.glCallList(list);
        GL11.glPopMatrix();

        GL11.glDisable(GL11.GL_BLEND);

        GL11.glDisable(
                GL11.GL_TEXTURE_2D);
        mColor.reset();

        // Update the image id in the engine
        Engine engine = Engine.getInstance();
        if (engine.getMouseX() > mX && engine.getMouseX() < mX + width && engine.getMouseY() > mY && engine.getMouseY() < mY + height) {
            engine.setLastImageUnderMouse(getId(), new Vector2D(mX, mY),
                    new Vector2D(width, height));
        }
    }

    public void drawRotated(int mX, int mY, float mAngle) {
        GLColor mColor =
                new GLColor(color.getRed(), color.getGreen(), color.getBlue(),
                1.0f);
        mColor.set();
        GL11.glEnable(GL11.GL_TEXTURE_2D);

        GL11.glDisable(GL11.GL_DEPTH_TEST);
        GL11.glEnable(GL11.GL_BLEND);

        texture.bind();

        GL11.glMatrixMode(GL11.GL_MODELVIEW);
        GL11.glPushMatrix();
        {
            GL11.glTranslatef(mX, Engine.getInstance().getDisplayBounds().getY() - mY, 0.0f);
            GL11.glTranslatef(width / 2.0f, - height / 2.0f, 0.0f);
            GL11.glScaled(width, height, 0);
            GL11.glRotatef(mAngle, 0.0f, 0.0f, 1.0f);            
            //GL11.glTranslatef(mX + width / 2, Engine.getInstance().getDisplayBounds().getY() - mY - height/2, 0.0f);

            GL11.glCallList(list);
        }
        GL11.glPopMatrix();

        GL11.glDisable(GL11.GL_BLEND);
        GL11.glDisable(GL11.GL_TEXTURE_2D);
        mColor.reset();

        Engine.drawDot(mX, mY, 0, 5.0f, GLColor.RED);
        Engine.drawRect(mX, mY, width, height, 1.0f, GLColor.YELLOW);
    }

    /**
     * Clones this object
     * 
     * @return A new image instance
     */
    public Object clone() {
        return new GLImage((GLTexture) texture.clone(), width, height, tile);
    }
}